<script lang="tsx" setup>
import { createReusableTemplate } from '@vueuse/core';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { localStg } from '@/utils/storage';
import { $t } from '@/locales';

defineOptions({ name: 'JarServer' });

/** 运行状态：-1- 待机， 0-未运行，1-运行中，2-检查中 */
type RunStatus = -1 | 0 | 1 | 2;
/** 校验状态：-1- 未校验，0-校验失败，1-校验成功 */
type VerifyStatus = -1 | 0 | 1;

/** 路径校验对象 */
interface PathVerify {
    path: string | null;
    status: VerifyStatus;
    loading: boolean;
}

/** Jar 服务需要的内容 */
interface JarServer {
    // 服务端口
    port: number;
    jdkPath: PathVerify;
    jarPath: PathVerify;
    runStatus: RunStatus;
    isRunning: boolean;
    runLoading: boolean;
    isHealthChecking: boolean;
    healthCheckTimeout: number; // 健康检查超时时间（秒）
}

const { define: IconDefineTemplate, reuse: IconReuseTemplate } = createReusableTemplate();
const { define: RunIconDefineTemplate, reuse: RunIconReuseTemplate } = createReusableTemplate();

/** 表单数据 */
const formRef = ref();
const model = ref<JarServer>({
    port: 10001,
    jdkPath: {
        path: localStg.get('jdkPath'),
        status: -1,
        loading: false
    },
    jarPath: {
        path: localStg.get('jarPath'),
        status: -1,
        loading: false
    },
    runStatus: -1,
    isRunning: false,
    runLoading: false,
    isHealthChecking: false, // 新增健康检查状态
    healthCheckTimeout: localStg.get('healthCheckTimeout') || 30 // 默认30秒，从本地存储获取
});

/** 计算运行状态 */
const computedRunStatus = computed<RunStatus>(() => {
    const { jdkPath, jarPath, isRunning, isHealthChecking } = model.value;

    // 如果正在进行健康检查，返回检查中状态
    if (isHealthChecking) {
        return 2;
    }

    // 如果正在运行，返回运行中状态
    if (isRunning) {
        return 1;
    }

    // 如果 JDK 和 JAR 都校验成功，返回未运行状态
    if (jdkPath.status === 1 && jarPath.status === 1) {
        return 0;
    }

    // 其他情况返回待机状态
    return -1;
});

/** 是否可以运行服务 */
const canRunService = computed(() => {
    return (
        model.value.jdkPath.status === 1 &&
        model.value.jarPath.status === 1 &&
        !model.value.isRunning &&
        !model.value.runLoading
    );
});

/** 监听计算的运行状态变化 */
watch(computedRunStatus, (newStatus: any) => {
    model.value.runStatus = newStatus;
});

/** 根据校验状态获取按钮类型 */
function getButtonType(status: VerifyStatus) {
    switch (status) {
        case -1:
            return 'info';
        case 0:
            return 'error';
        case 1:
            return 'success';
        default:
            return 'info';
    }
}

/** 校验 JDK 路径内容: 指定路径下执行 java --version 命令判断是否存在 JDK */
// eslint-disable-next-line complexity
async function handlerJdkPathVerify(isInit: boolean = false) {
    try {
        model.value.jdkPath.loading = true;

        // 是否未校验
        const isNotVerify = model.value.jdkPath.status === -1;

        // 选择 JDK 目录
        const jdkPath =
            model.value.jdkPath.path && isNotVerify
                ? model.value.jdkPath.path
                : await window?.electronAPI?.selectJdkDirectory();
        if (!jdkPath) {
            return;
        }

        // 更新路径
        model.value.jdkPath.path = jdkPath;

        // 执行 JDK 验证
        const result = await window?.electronAPI?.verifyJdkPath(jdkPath);

        if (result) {
            // 缓存验证结果
            localStg.set('jdkPath', jdkPath);

            // 更新状态
            model.value.jdkPath.status = result.success ? 1 : 0;

            if (!isInit) {
                if (result.success) {
                    window?.$message?.success(`${$t('page.home.jarServer.jdkPathValid')}: ${result.version}`);
                } else {
                    window?.$message?.error($t('page.home.jarServer.jdkPathInvalid'));
                }
            }
        }
    } catch {
        model.value.jdkPath.status = 0;
        window.$message?.error($t('page.home.jarServer.jdkPathVerifyFailed'));
    } finally {
        model.value.jdkPath.loading = false;
    }
}

/** 校验 JAR 路径内容: 指定路径下判断是否为 jar 文件 */
// eslint-disable-next-line complexity
async function handlerJarPathVerify(isInit: boolean = false) {
    try {
        model.value.jarPath.loading = true;

        // 是否未校验
        const isNotVerify = model.value.jarPath.status === -1;

        // 选择 JAR 文件
        const jarPath =
            model.value.jarPath.path && isNotVerify
                ? model.value.jarPath.path
                : await window?.electronAPI?.selectJarFile();

        if (!jarPath) {
            return;
        }

        // 更新路径
        model.value.jarPath.path = jarPath;

        // 执行 JAR 验证
        const result = await window?.electronAPI?.verifyJarFile(jarPath);

        if (result) {
            // 缓存验证结果
            localStg.set('jarPath', jarPath);

            // 更新状态
            model.value.jarPath.status = result.success ? 1 : 0;

            // 显示消息
            if (!isInit) {
                if (result.success && result.fileName && result.fileSize) {
                    window.$message?.success(
                        `${$t('page.home.jarServer.jarPathValid')}: ${result.fileName} (${formatFileSize(result.fileSize)})`
                    );
                } else {
                    window.$message?.error($t('page.home.jarServer.jarPathInvalid'));
                }
            }
        }
    } catch {
        model.value.jarPath.status = 0;
        window.$message?.error($t('page.home.jarServer.jarFileVerifyFailed'));
    } finally {
        model.value.jarPath.loading = false;
    }
}

/** 运行 JAR 服务 */
async function handlerRunService() {
    if (!canRunService.value) {
        window.$message?.warning($t('page.home.jarServer.pleaseVerifyPaths'));
        return;
    }

    try {
        model.value.runLoading = true;
        model.value.isHealthChecking = true; // 开始健康检查状态

        // 开始健康检查
        startHealthCheck();

        // 调用 Electron API 启动服务
        const result = await window?.electronAPI?.startJarService({
            jdkPath: model.value.jdkPath.path!,
            jarPath: model.value.jarPath.path!,
            port: 10001,
            active: 'dev'
        });

        console.log('start jar result: ', result);

        if (result?.success) {
            window.$message?.success($t('page.home.jarServer.serviceStartSuccess'));
        } else {
            model.value.isHealthChecking = false; // 启动失败，停止健康检查状态
            window.$message?.error(result?.message || $t('page.home.jarServer.serviceStartFailed'));
        }
    } catch {
        model.value.isHealthChecking = false; // 异常时停止健康检查状态
        window.$message?.error($t('page.home.jarServer.serviceStartFailed'));
    } finally {
        model.value.runLoading = false;
    }
}

/** 停止 JAR 服务 */
async function handlerStopService() {
    try {
        model.value.runLoading = true;

        // 调用 Electron API 停止服务
        const result = await window?.electronAPI?.stopJarService();

        if (result?.success) {
            model.value.isRunning = false;
            model.value.isHealthChecking = false; // 停止健康检查状态
            // 停止所有检查
            stopAllChecks();
        } else {
            window.$message?.error(result?.message || $t('page.home.jarServer.serviceStopFailed'));
        }
    } catch {
        window.$message?.error($t('page.home.jarServer.serviceStopFailed'));
    } finally {
        model.value.runLoading = false;
    }
}

/** 健康检查定时器 */
let healthCheckTimer: number | null = null;
let healthCheckStartTime: number = 0;
// 动态获取健康检查超时时间
const getHealthCheckTimeout = () => model.value.healthCheckTimeout * 1000; // 转换为毫秒

/** 端口检测定时器 */
let portCheckTimer: number | null = null;
let portCheckStartTime: number = 0;
// 动态获取端口检查超时时间（使用相同的超时设置）
const getPortCheckTimeout = () => model.value.healthCheckTimeout * 1000; // 转换为毫秒

/** 检查端口是否被占用 */
async function checkPortOccupied() {
    try {
        const result = await window?.electronAPI?.checkPortOccupied(model.value.port);
        return result;
    } catch (error) {
        console.error('检查端口占用失败:', error);
        return {
            success: false,
            occupied: false,
            message: $t('page.home.jarServer.portCheckFailed')
        };
    }
}

/** 开始端口检测和健康检查 */
async function startPortCheckAndHealthCheck() {
    // 首先检查端口是否被占用
    const portResult = await checkPortOccupied();

    if (!portResult?.success) {
        window.$message?.error(portResult?.message || $t('page.home.jarServer.portCheckFailed'));
        return;
    }

    if (portResult.occupied) {
        // 端口被占用，开始健康检查
        window.$message?.info($t('page.home.jarServer.portOccupiedDetected'));
        startHealthCheckForOccupiedPort();
    } else {
        // 端口未被占用，更新状态
        model.value.isRunning = false;
    }
}

/** 为被占用的端口开始健康检查 */
function startHealthCheckForOccupiedPort() {
    portCheckStartTime = Date.now();
    model.value.isHealthChecking = true; // 开始健康检查状态

    portCheckTimer = window.setInterval(async () => {
        try {
            const result = await window?.electronAPI?.checkServiceHealth();

            if (result?.success) {
                // 健康检查成功，说明服务正在运行
                stopPortCheck();
                model.value.isRunning = true;
                model.value.isHealthChecking = false; // 停止健康检查状态
                window.$message?.success($t('page.home.jarServer.serviceRunningDetected'));
                return;
            }

            // 检查是否超时
            if (Date.now() - portCheckStartTime > getPortCheckTimeout()) {
                // 超时，显示端口被占用提示
                stopPortCheck();
                model.value.isHealthChecking = false; // 停止健康检查状态
                window.$message?.warning($t('page.home.jarServer.portOccupied'));
                model.value.isRunning = false;
            }
        } catch (error) {
            console.error('端口健康检查失败:', error);
        }
    }, 2000); // 每2秒检查一次
}

/** 停止端口检测 */
function stopPortCheck() {
    if (portCheckTimer) {
        clearInterval(portCheckTimer);
        portCheckTimer = null;
    }
    model.value.isHealthChecking = false; // 停止健康检查状态
}

/** 开始健康检查 */
function startHealthCheck() {
    healthCheckStartTime = Date.now();
    model.value.isHealthChecking = true; // 开始健康检查状态

    healthCheckTimer = window.setInterval(async () => {
        try {
            const result = await window?.electronAPI?.checkServiceHealth();
            console.log('result: ', result);
            if (result?.success) {
                // 健康检查成功，停止检查
                stopHealthCheck();
                model.value.isRunning = true;
                model.value.isHealthChecking = false; // 停止健康检查状态
                window.$message?.success($t('page.home.jarServer.serviceRunningNormal'));
                return;
            }

            // 检查是否超时
            if (Date.now() - healthCheckStartTime > getHealthCheckTimeout()) {
                // 超时，停止服务
                stopHealthCheck();
                model.value.isHealthChecking = false; // 停止健康检查状态
                await handlerStopService();
                window.$message?.error(
                    $t('page.home.jarServer.serviceStartTimeout', { timeout: model.value.healthCheckTimeout })
                );
            }
        } catch (error) {
            console.error('健康检查失败:', error);
        }
    }, 2000); // 每2秒检查一次
}

/** 停止健康检查 */
function stopHealthCheck() {
    if (healthCheckTimer) {
        clearInterval(healthCheckTimer);
        healthCheckTimer = null;
    }
    model.value.isHealthChecking = false; // 停止健康检查状态
}

/** 停止所有检查 */
function stopAllChecks() {
    stopHealthCheck();
    stopPortCheck();
    model.value.isHealthChecking = false; // 停止健康检查状态
}

/** 格式化文件大小 */
function formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

/** 监听健康检查超时时间变化，保存到本地存储 */
watch(
    () => model.value.healthCheckTimeout,
    (newTimeout) => {
        if (newTimeout && newTimeout > 0) {
            localStg.set('healthCheckTimeout', newTimeout);
        }
    }
);

const runningShowMsg = computed(() => {
    const runStatus = model.value.runStatus;
    if (runStatus === -1) {
        return $t('page.home.jarServer.standby');
    } else if (runStatus === 0) {
        return $t('page.home.jarServer.notRunning');
    } else if (runStatus === 1) {
        return $t('page.home.jarServer.running');
    } else if (runStatus === 2) {
        return $t('page.home.jarServer.checking');
    } else {
        return '';
    }
});

/** 初始化 */
function init() {
    // 如果 JAR 有值默认校验一次
    if (model.value.jarPath.path) {
        handlerJarPathVerify(true);
    }

    // 如果 JDK 有值默认校验一次
    if (model.value.jdkPath.path) {
        handlerJdkPathVerify(true);
    }

    // 程序加载时自动检测端口占用情况
    startPortCheckAndHealthCheck();

    // 显示初始化消息
    const jdkSuccess = model.value.jdkPath.status === 1;
    const jarSuccess = model.value.jarPath.status === 1;
    
    if (jdkSuccess && jarSuccess) {
        window.$message?.success($t('page.home.jarServer.initComplete'));
    } else if (jdkSuccess || jarSuccess) {
        window.$message?.warning($t('page.home.jarServer.initCompleteWithWarnings'));
    } else {
        window.$message?.info($t('page.home.jarServer.initCompleteVerifyPaths'));
    }
}

onMounted(() => {
    init();
});

// 组件卸载时清理定时器
onUnmounted(() => {
    stopAllChecks();
});
</script>

<template>
    <!-- define component start: IconReuseTemplate -->
    <IconDefineTemplate v-slot="{ status }">
        <icon-solar-menu-dots-linear v-if="status === -1"></icon-solar-menu-dots-linear>
        <icon-mdi-close-circle v-else-if="status === 0"></icon-mdi-close-circle>
        <icon-mdi-check-circle v-else-if="status === 1"></icon-mdi-check-circle>
    </IconDefineTemplate>
    <!-- define component end: IconReuseTemplate -->

    <!-- define component start: RunIconReuseTemplate -->
    <RunIconDefineTemplate v-slot="{ status }">
        <icon-mdi-sleep v-if="status === -1"></icon-mdi-sleep>
        <icon-mdi-play v-else-if="status === 0"></icon-mdi-play>
        <icon-mdi-loading v-else-if="status === 1" class="animate-spin"></icon-mdi-loading>
        <icon-mdi-loading
            v-else-if="status === 2"
            class="animate-spin text-orange-500"
        ></icon-mdi-loading>
    </RunIconDefineTemplate>
    <!-- define component end: RunIconReuseTemplate -->

    <NForm ref="formRef" :model="model">
        <NGrid x-gap="5" y-gap="5">
            <!-- JDK 路径校验 -->
            <NFormItemGi span="24" :label="$t('page.home.jarServer.jdkPath')" prop="jdkPath">
                <NInputGroup>
                    <NInput
                        v-model:value="model.jdkPath.path"
                        readonly
                        :placeholder="$t('page.home.jarServer.jdkPathPlaceholder')"
                    />
                    <!-- 检查按钮  -->
                    <NButton
                        :loading="model.jdkPath.loading"
                        :type="getButtonType(model.jdkPath.status)"
                        @click="handlerJdkPathVerify"
                    >
                        <template #icon>
                            <IconReuseTemplate :status="model.jdkPath.status" />
                        </template>
                    </NButton>
                </NInputGroup>
            </NFormItemGi>
            <!-- JAR 路径校验 -->
            <NFormItemGi span="24" :label="$t('page.home.jarServer.jarPath')" prop="jarPath">
                <NInputGroup>
                    <NInput
                        v-model:value="model.jarPath.path"
                        readonly
                        :placeholder="$t('page.home.jarServer.jarPathPlaceholder')"
                    />
                    <!-- 检查按钮  -->
                    <NButton
                        :loading="model.jarPath.loading"
                        :type="getButtonType(model.jarPath.status)"
                        @click="handlerJarPathVerify"
                    >
                        <template #icon>
                            <IconReuseTemplate :status="model.jarPath.status" />
                        </template>
                    </NButton>
                </NInputGroup>
            </NFormItemGi>
            <!-- 端口 -->
            <NFormItemGi
                span="12"
                class="w-100%"
                :label="$t('page.home.jarServer.port')"
                prop="port"
            >
                <NInputNumber
                    class="w-100%"
                    v-model:value="model.port"
                    readonly
                    placeholder="$t('page.home.jarServer.selectJarFilePlaceholder')"
                />
            </NFormItemGi>
            <!-- 健康检查超时时间 -->
            <NFormItemGi
                span="12"
                class="w-100%"
                :label="$t('page.home.jarServer.healthCheckTimeout')"
                prop="healthCheckTimeout"
            >
                <NInputNumber
                    class="w-100%"
                    v-model:value="model.healthCheckTimeout"
                    :min="5"
                    :max="300"
                    :placeholder="$t('page.home.jarServer.healthCheckTimeout')"
                />
            </NFormItemGi>
            <!-- 服务运行状态 -->
            <NFormItemGi span="24" :label="$t('page.home.jarServer.runStatus')" prop="runStatus">
                <NInputGroup>
                    <NInput v-model:value="runningShowMsg" readonly />
                    <!-- 运行/停止按钮 -->
                    <NButton
                        v-if="model.runStatus === 0"
                        :loading="model.runLoading"
                        :disabled="!canRunService"
                        type="primary"
                        @click="handlerRunService"
                    >
                        <template #icon>
                            <RunIconReuseTemplate :status="0" />
                        </template>
                    </NButton>
                    <NButton
                        v-else-if="model.runStatus === 1"
                        :loading="model.runLoading"
                        type="error"
                        @click="handlerStopService"
                    >
                        <template #icon>
                            <icon-mdi-stop />
                        </template>
                    </NButton>
                    <NButton
                        v-else-if="model.runStatus === 2"
                        :loading="model.runLoading"
                        type="warning"
                        disabled
                    >
                        <template #icon>
                            <RunIconReuseTemplate :status="2" />
                        </template>
                    </NButton>
                    <NButton v-else disabled>
                        <template #icon>
                            <RunIconReuseTemplate :status="-1" />
                        </template>
                    </NButton>
                </NInputGroup>
            </NFormItemGi>
        </NGrid>
    </NForm>
</template>
